﻿using System;

namespace Gmantis.Zip.ZLib
{
    internal class Adler32 : IChecksum
    {
        // Fields
        private long _adler = 1L;
        private const int BASE = 0xfff1;
        private const int NMAX = 0x15b0;

        // Methods
        public long checkSum(long value, byte[] buf, int index, int len)
        {
            if ((value == 1L) || (buf == null))
            {
                this.reset();
            }
            if (buf != null)
            {
                this.update(buf, index, len);
            }
            return this.getValue();
        }

        private long getValue()
        {
            return this._adler;
        }

        private void reset()
        {
            this._adler = 1L;
        }

        private void update(byte[] b, int off, int len)
        {
            if (((b == null) || (off < 0)) || ((len < 0) || ((off + len) > b.Length)))
            {
                throw new ArgumentException(StringTables.GetString("Bad parameters in call to Adler.update."));
            }
            long num = this._adler & 0xffffL;
            long num2 = (this._adler >> 0x10) & 0xffffL;
            while (len > 0)
            {
                int num3 = (len < 0x15b0) ? len : 0x15b0;
                len -= num3;
                while (num3 >= 0x10)
                {
                    num2 += num += b[off] & 0xff;
                    off++;
                    num2 += num += b[off] & 0xff;
                    off++;
                    num2 += num += b[off] & 0xff;
                    off++;
                    num2 += num += b[off] & 0xff;
                    off++;
                    num2 += num += b[off] & 0xff;
                    off++;
                    num2 += num += b[off] & 0xff;
                    off++;
                    num2 += num += b[off] & 0xff;
                    off++;
                    num2 += num += b[off] & 0xff;
                    off++;
                    num2 += num += b[off] & 0xff;
                    off++;
                    num2 += num += b[off] & 0xff;
                    off++;
                    num2 += num += b[off] & 0xff;
                    off++;
                    num2 += num += b[off] & 0xff;
                    off++;
                    num2 += num += b[off] & 0xff;
                    off++;
                    num2 += num += b[off] & 0xff;
                    off++;
                    num2 += num += b[off] & 0xff;
                    off++;
                    num2 += num += b[off] & 0xff;
                    off++;
                    num3 -= 0x10;
                }
                while (num3 != 0)
                {
                    num2 += num += b[off] & 0xff;
                    off++;
                    num3--;
                }
                num = num % 0xfff1L;
                num2 = num2 % 0xfff1L;
            }
            this._adler = (num2 << 0x10) | num;
        }
    }
}
